﻿using System;
using System.Collections.Generic;
using System.Linq;
using DeltaGroup.WheelOfJeopardy.Model;
using DeltaGroup.WheelOfJeopardy.UI.Events;

namespace DeltaGroup.WheelOfJeopardy.GameManager
{
    public class FinalJeopardyRound : Round
    {
        #region Fields

        private readonly Challenge _challenge;
        private readonly DifficultyLevel _difficulty;
        private readonly List<Contestant> _contestants;
        private readonly IGameSettings _settings;

        private Contestant _currentContestant;

        private Queue<Contestant> _participants;

        #endregion Fields

        #region Constructors

        /// <summary>
        ///     Initializes a new instance of the <see cref = "FinalJeopardyRound" /> class.
        /// </summary>
        /// <param name = "settings">game settings</param>
        /// <param name = "challenge">The challenge.</param>
        /// <param name = "contestants">The contestants.</param>
        /// <param name="difficulty">Game Difficulty</param>
        public FinalJeopardyRound(IGameSettings settings, Challenge challenge, List<Contestant> contestants, DifficultyLevel difficulty)
        {
            _settings = settings;
            _challenge = challenge;
            _difficulty = difficulty;
            _contestants = contestants;
        }

        #endregion Constructors

        #region Properties

        public Challenge FinalChallenge { get; private set; }

        public List<Contestant> ParticipatingContestants
        {
            get
            {
                return _participants.ToList();
            }
        }

        public Dictionary<string, int> FinalJeopardyResult { get; private set; }

        /// <summary>
        ///     Gets or sets the challenge manager.
        /// </summary>
        /// <value>The challenge manager.</value>
        public IChallengeManager ChallengeManager { get; set; }

        /// <summary>
        ///     Gets or sets the UI manager.
        /// </summary>
        /// <value>The UI manager.</value>
        public IFinalJeopardyUIManager UIManager { get; set; }

        #endregion Properties

        #region Methods

        /// <summary>
        ///     Starts this Round.
        /// </summary>
        public override void Start()
        {
            UIManager.ChallengeResponseReceived += HandleResponse;
            UIManager.ResponseTimerExpired += HandleTimerExpiration;
            UIManager.WagerReceived += HandleWager;

            _participants = new Queue<Contestant>(_contestants.Where(x => x.Score > 0));
            FinalJeopardyResult = new Dictionary<string, int>();

            NextContestantPlay();
        }

        /// <summary>
        ///     Finishes the round.
        /// </summary>
        private void FinishRound()
        {
            _currentContestant = null;
            UIManager.ChallengeResponseReceived -= HandleResponse;
            UIManager.ResponseTimerExpired -= HandleTimerExpiration;

            RaiseRoundFinished();
        }

        /// <summary>
        ///     Handles the response.
        /// </summary>
        /// <param name = "sender">The sender.</param>
        /// <param name = "e">The <see cref = "ChallengeResponseReceivedEventArgs" /> instance containing the event data.</param>
        private void HandleResponse(object sender, ChallengeResponseReceivedEventArgs e)
        {
            var response = e.Response;

            int point = 0;

            if (ChallengeManager.IsResponseCorrect(_difficulty, FinalChallenge, response))
            {
                point = FinalChallenge.Point;
            }
            else
            {
                point = FinalChallenge.Point * -1;
            }

            _currentContestant.Score += point;
            FinalJeopardyResult.Add(_currentContestant.Name, point);

            NextContestantPlay();
        }

        /// <summary>
        ///     Handles the timer expiration.
        /// </summary>
        /// <param name = "sender">The sender.</param>
        /// <param name = "e">The <see cref = "System.EventArgs" /> instance containing the event data.</param>
        private void HandleTimerExpiration(object sender, EventArgs e)
        {
            NextContestantPlay();
        }

        /// <summary>
        ///     Handles the wager.
        /// </summary>
        /// <param name = "sender">The sender.</param>
        /// <param name = "e">The <see cref = "DeltaGroup.WheelOfJeopardy.UI.Events.WagerReceivedEventArgs" /> instance containing the event data.</param>
        private void HandleWager(object sender, WagerReceivedEventArgs e)
        {
            FinalChallenge = new Challenge(_challenge) {Point = e.Wager};

            UIManager.PromptForResponse(_challenge, _settings.GetResponseTimeLimit(_difficulty));
        }

        /// <summary>
        ///     Nexts the contestant play.
        /// </summary>
        private void NextContestantPlay()
        {
            if (_participants.Count == 0)
            {
                FinishRound();
            }
            else
            {
                if (_currentContestant != null)
                    _currentContestant.IsPlaying = false;

                _currentContestant = _participants.Dequeue();
                
                _currentContestant.IsPlaying = true;

                UIManager.PromptForWager(_currentContestant.Score);
            }
        }

        #endregion Methods
    }
}